// 由于 STB_IMAGE_IMPLEMENTATION 将 std_image 被编译为 .cpp 文件，因此不放在头文件中
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>

#include "GLProgram.h"
#include "GLScene.h"

// 静态本地变量
GLCamera GLProgram::s_camera;
bool GLProgram::s_moving = false;
GLProgram* GLProgram::s_program = nullptr;

GLProgram::GLProgram(int width, int height, const char* title, int& flag) : m_shader(nullptr), m_scene(nullptr)
{
	// 初始化
	glfwInit();

	// 配置版本信息，启用核心模式
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

	m_window = glfwCreateWindow(width, height, title, 0, 0);
	if (m_window == NULL)
	{
		std::cout << "Failed to create GLFW window" << std::endl;
		glfwTerminate();
		flag = -1;
		return;
	}
	glfwMakeContextCurrent(m_window);

	// 初始化 GLAD 来管理 OpenGL 函数指针
	if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
	{
		std::cout << "Failed to initialize GLAD" << std::endl;
		flag = -1;
		return;
	}

	// 设置视口
	glViewport(0, 0, width, height);

	// 注册函数
	glfwSetFramebufferSizeCallback(m_window, GLFWWindowResize);
	glfwSetScrollCallback(m_window, GLFWScrollCallback);
	glfwSetMouseButtonCallback(m_window, GLFWMouseButtonCallback);
	glfwSetCursorPosCallback(m_window, GLFWCursorPosCallback);

	// 生成默认纹理构造
	GenerateTexture(TEXTURE::RED);
	BindTexture(TEXTURE::RED);
	LoadTexture(TEXTURE::RED);

	GenerateTexture(TEXTURE::GREEN);
	BindTexture(TEXTURE::GREEN);
	LoadTexture(TEXTURE::GREEN);

	GenerateTexture(TEXTURE::BLUE);
	BindTexture(TEXTURE::BLUE);
	LoadTexture(TEXTURE::BLUE);

	GenerateTexture(TEXTURE::YELLOW);
	BindTexture(TEXTURE::YELLOW);
	LoadTexture(TEXTURE::YELLOW);

	GenerateTexture(TEXTURE::WHITE);
	BindTexture(TEXTURE::WHITE);
	LoadTexture(TEXTURE::WHITE);

	GenerateTexture(TEXTURE::BLACK);
	BindTexture(TEXTURE::BLACK);
	LoadTexture(TEXTURE::BLACK);

	GenerateTexture(TEXTURE::CHESS);
	BindTexture(TEXTURE::CHESS);
	LoadTexture(TEXTURE::CHESS);
}

GLProgram::~GLProgram()
{
	// 销毁着色器
	for (auto it = m_shaders.begin(); it != m_shaders.end(); ++it)
		delete it->second;

	// 销毁环境
	delete m_scene;

	// 销毁资源
	glfwTerminate();
}

GLProgram* GLProgram::CreateProgram(int width, int height, const char* title, int& flag)
{
	if (s_program == nullptr)
		s_program = new GLProgram(width, height, title, flag);

	return s_program;
}

GLProgram* GLProgram::ShareProgram()
{
	return s_program;
}

void GLProgram::DeleteProgram()
{
	if (s_program != nullptr)
		delete s_program;
}

GLScene* GLProgram::ShareScene()
{
	if (m_scene == nullptr)
		m_scene = new GLScene;
	return m_scene;
}

void GLProgram::SetUniformInt(const char* var, int val)
{
	glUniform1i(glGetUniformLocation(m_shader->m_ID, var), val);
}

void GLProgram::SetUniformFloat(const char* var, float val)
{
	glUniform1f(glGetUniformLocation(m_shader->m_ID, var), val);
}

void GLProgram::SetUniformVec2(const char* var, const float* val)
{
	unsigned int loc = glGetUniformLocation(m_shader->m_ID, var);
	glUniform2fv(loc, 1, val);
}

void GLProgram::SetUniformVec2(const char* var, float x, float y)
{
	unsigned int loc = glGetUniformLocation(m_shader->m_ID, var);
	glUniform2f(loc, x, y);
}

void GLProgram::SetUniformVec3(const char* var, const float* val)
{
	unsigned int loc = glGetUniformLocation(m_shader->m_ID, var);
	glUniform3fv(loc, 1, val);
}

void GLProgram::SetUniformVec3(const char* var, float x, float y, float z)
{
	unsigned int loc = glGetUniformLocation(m_shader->m_ID, var);
	glUniform3f(loc, x, y, z);
}

void GLProgram::SetUniformVec4(const char* var, const float* val)
{
	unsigned int loc = glGetUniformLocation(m_shader->m_ID, var);
	glUniform4fv(loc, 1, val);
}

void GLProgram::SetUniformVec4(const char* var, float x, float y, float z, float w)
{
	unsigned int loc = glGetUniformLocation(m_shader->m_ID, var);
	glUniform4f(loc, x, y, z, w);
}

void GLProgram::SetUniformMatrix4fv(const char* var, const float* val)
{
	unsigned int loc = glGetUniformLocation(m_shader->m_ID, var);
	glUniformMatrix4fv(loc, 1, GL_FALSE, val);
}

void GLProgram::SetUniformBlock(const char* var, int i)
{
	unsigned int index = glGetUniformBlockIndex(m_shader->m_ID, var);
	glUniformBlockBinding(m_shader->m_ID, index, i);
}

void GLProgram::SetDirLight(glm::vec3 direction, glm::vec3 ambient, glm::vec3 diffuse, glm::vec3 specular)
{
	SetUniformVec3("dirLight.direction", glm::value_ptr(direction));
	SetUniformVec3("dirLight.ambient", glm::value_ptr(ambient));
	SetUniformVec3("dirLight.diffuse", glm::value_ptr(diffuse));
	SetUniformVec3("dirLight.specular", glm::value_ptr(specular));
}

void GLProgram::SetPointLight(int i, glm::vec3 position, glm::vec3 ambient, glm::vec3 diffuse, glm::vec3 specular)
{
	// 转为字符串
	char c[255];
	itoa(i, c, 10);
	std::string index = c;
	std::string s_position = "pointLights[" + index + "].position";
	std::string s_ambient = "pointLights[" + index + "].ambient";
	std::string s_diffuse = "pointLights[" + index + "].diffuse";
	std::string s_specular = "pointLights[" + index + "].specular";
	std::string s_constant = "pointLights[" + index + "].constant";
	std::string s_linear = "pointLights[" + index + "].linear";
	std::string s_quadratic = "pointLights[" + index + "].quadratic";

	SetUniformVec3(s_position.c_str(), glm::value_ptr(position));
	SetUniformVec3(s_ambient.c_str(), glm::value_ptr(ambient));
	SetUniformVec3(s_diffuse.c_str(), glm::value_ptr(diffuse));
	SetUniformVec3(s_specular.c_str(), glm::value_ptr(specular));
	SetUniformFloat(s_constant.c_str(), 1.0f);
	SetUniformFloat(s_linear.c_str(), 0.09f);
	SetUniformFloat(s_quadratic.c_str(), 0.032f);
}

void GLProgram::SetSpotLight(int i, glm::vec3 position, glm::vec3 direction, glm::vec3 ambient, glm::vec3 diffuse, glm::vec3 specular)
{
	char c[255];
	itoa(i, c, 10);
	std::string index = c;
	std::string s_position = "spotLights[" + index + "].position";
	std::string s_direction = "spotLights[" + index + "].direction";
	std::string s_ambient = "spotLights[" + index + "].ambient";
	std::string s_diffuse = "spotLights[" + index + "].diffuse";
	std::string s_specular = "spotLights[" + index + "].specular";
	std::string s_constant = "spotLights[" + index + "].constant";
	std::string s_linear = "spotLights[" + index + "].linear";
	std::string s_quadratic = "spotLights[" + index + "].quadratic";
	std::string s_cutOff = "spotLights[" + index + "].cutOff";
	std::string s_outerCutOff = "spotLights[" + index + "].outerCutOff";

	SetUniformVec3(s_position.c_str(), glm::value_ptr(position));
	SetUniformVec3(s_direction.c_str(), glm::value_ptr(direction));
	SetUniformVec3(s_ambient.c_str(), glm::value_ptr(ambient));
	SetUniformVec3(s_diffuse.c_str(), glm::value_ptr(diffuse));
	SetUniformVec3(s_specular.c_str(), glm::value_ptr(specular));
	SetUniformFloat(s_constant.c_str(), 1.0f);
	SetUniformFloat(s_linear.c_str(), 0.09f);
	SetUniformFloat(s_quadratic.c_str(), 0.032f);
	SetUniformFloat(s_cutOff.c_str(), glm::cos(glm::radians(12.5f)));
	SetUniformFloat(s_outerCutOff.c_str(), glm::cos(glm::radians(15.0f)));
}

void GLProgram::GenerateProgram(int i, const char* vertexPath, const char* fragmentPath, const char* geometryPath)
{
	m_shaders[i] = new GLShader(vertexPath, fragmentPath, geometryPath);
}

void GLProgram::UseProgram(int i)
{
	if (m_shaders.count(i) == 0)
	{
		std::cout << "Program don't exist." << std::endl;
		return;
	}

	m_shader = m_shaders[i];
	m_shader->EnableShader();
}

void GLProgram::InitProgram()
{
	// 获得观察位置
	glm::vec3 pos = s_camera.GetPosition();
	SetUniformVec3("viewPos", glm::value_ptr(pos));

	// 这里只移动相机
	glm::mat4 model = glm::mat4(1.0f);
	glm::mat4 view = s_camera.GetViewMatrix();
	glm::mat4 projection = glm::perspective(glm::radians(45.0f), 1.0f, 0.1f, 1000.0f);
	SetUniformMatrix4fv("model", glm::value_ptr(model));
	SetUniformMatrix4fv("view", glm::value_ptr(view));
	SetUniformMatrix4fv("projection", glm::value_ptr(projection));

	// 传入法线修正矩阵
	glm::mat4 fix = glm::transpose(glm::inverse(model));
	SetUniformMatrix4fv("fix", glm::value_ptr(fix));
}

void GLProgram::GenerateArray(int i)
{
	unsigned int VAO, VBO, EBO, Ins;

	glGenVertexArrays(1, &VAO);
	glGenBuffers(1, &VBO);
	glGenBuffers(1, &EBO);
	glGenBuffers(1, &Ins);

	m_VAOs[i] = VAO;
	m_VBOs[i] = VBO;
	m_EBOs[i] = EBO;
	m_Inss[i] = Ins;
}

void GLProgram::BindArray(int i)
{
	if (m_VAOs.count(i) == 0)
	{
		std::cout << "Array don't exist." << std::endl;
		return;
	}

	glBindVertexArray(m_VAOs[i]);
	glBindBuffer(GL_ARRAY_BUFFER, m_VBOs[i]);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_EBOs[i]);
}

void GLProgram::BindInsArray(int i)
{
	if (m_Inss.count(i) == 0)
	{
		std::cout << "Instance don't exist." << std::endl;
		return;
	}

	glBindBuffer(GL_ARRAY_BUFFER, m_Inss[i]);
}

void GLProgram::UnbindArray()
{
	glBindVertexArray(0);
	glBindBuffer(GL_ARRAY_BUFFER, 0);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}

void GLProgram::GenerateUBO(int i)
{
	unsigned int UBO;

	// 生成后直接绑定到 i 号位
	glGenBuffers(1, &UBO);
	glBindBufferBase(GL_UNIFORM_BUFFER, i, UBO);

	m_UBOs[i] = UBO;
}

void GLProgram::BindUBO(int i)
{
	if (m_UBOs.count(i) == 0)
	{
		std::cout << "UBO don't exist." << std::endl;
		return;
	}

	glBindBuffer(GL_UNIFORM_BUFFER, m_UBOs[i]);
}

void GLProgram::UnbindUBO()
{
	glBindBuffer(GL_UNIFORM_BUFFER, 0);
}

void GLProgram::GenerateTexture(int i)
{
	unsigned int texture;
	glGenTextures(1, &texture);
	m_textures[i] = texture;
}

void GLProgram::LoadTexture(const char* file)
{
	// 加载图片前翻转图片
	stbi_set_flip_vertically_on_load(true);

	// glTexImage2D 生成纹理，然后 glGenerateMipmap 产生多级渐远纹理
	int width, height, nrComponents;
	unsigned char* data = stbi_load(file, &width, &height, &nrComponents, 0);
	if (data)
	{
		// 判定图像数据类型
		GLenum format = GL_RGB;
		if (nrComponents == 1)
			format = GL_RED;
		else if (nrComponents == 3)
			format = GL_RGB;
		else if (nrComponents == 4)
			format = GL_RGBA;

		glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
		glGenerateMipmap(GL_TEXTURE_2D);

		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

		stbi_image_free(data);
	}
	else
	{
		std::cout << "Texture failed to load at path: " << file << std::endl;
		stbi_image_free(data);
	}
}

void GLProgram::LoadTexture(TEXTURE texture, float a)
{
	float rgba[] = { 0, 0, 0, a };

	switch (texture)
	{
	case TEXTURE::RED:
		rgba[0] = 1;
		break;
	case TEXTURE::GREEN:
		rgba[1] = 1;
		break;
	case TEXTURE::BLUE:
		rgba[2] = 1;
		break;
	case TEXTURE::YELLOW:
		rgba[0] = rgba[1] = 1;
		break;
	case TEXTURE::WHITE:
		rgba[0] = rgba[1] = rgba[2] = 1;
		break;
	case TEXTURE::BLACK:
	case TEXTURE::CHESS:
		break;
	default:
		std::cout << "Texture don't exists." << std::endl;
		break;
	}

	// 生成纹理
	float texArray[16][16][4];
	for (int i = 0; i < 16; i++)
	{
		for (int j = 0; j < 16; j++)
		{
			if (texture == TEXTURE::CHESS && (i + j) % 2 == 0)
			{
				texArray[i][j][0] = 1;
				texArray[i][j][1] = 1;
				texArray[i][j][2] = 1;
				texArray[i][j][3] = 1;
			}
			else
			{
				texArray[i][j][0] = rgba[0];
				texArray[i][j][1] = rgba[1];
				texArray[i][j][2] = rgba[2];
				texArray[i][j][3] = rgba[3];
			}
		}
	}

	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_FLOAT, texArray);
	glGenerateMipmap(GL_TEXTURE_2D);

	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}

void GLProgram::LoadTexture(std::vector<const char*> files)
{
	// 取消纹理翻转
	stbi_set_flip_vertically_on_load(false);

	// glTexImage2D 生成纹理，然后 glGenerateMipmap 产生多级渐远纹理
	int width, height, nrComponents;
	for (unsigned int i = 0; i < files.size(); i++)
	{
		unsigned char* data = stbi_load(files[i], &width, &height, &nrComponents, 0);

		if (data)
		{
			// 判定图像数据类型
			GLenum format = GL_RGB;
			if (nrComponents == 1)
				format = GL_RED;
			else if (nrComponents == 3)
				format = GL_RGB;
			else if (nrComponents == 4)
				format = GL_RGBA;

			glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
			glGenerateMipmap(GL_TEXTURE_CUBE_MAP);

			stbi_image_free(data);
		}
		else
		{
			std::cout << "Texture failed to load at path: " << files[i] << std::endl;
			stbi_image_free(data);
		}
	}

	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}

void GLProgram::ActiveTexture(int i)
{
	glActiveTexture(GL_TEXTURE0 + i);
}

void GLProgram::BindTexture(int i)
{
	if (m_textures.count(i) == 0)
	{
		std::cout << "Array don't exist." << std::endl;
		return;
	}

	glBindTexture(GL_TEXTURE_2D, m_textures[i]);
}

void GLProgram::BindCubeTexture(int i)
{
	if (m_textures.count(i) == 0)
	{
		std::cout << "Array don't exist." << std::endl;
		return;
	}

	glBindTexture(GL_TEXTURE_CUBE_MAP, m_textures[i]);
}

void GLProgram::UnbindTexture()
{
	glBindTexture(GL_TEXTURE_2D, 0);
}

void GLProgram::GenerateFrame(int i)
{
	FrameID frameID;
	glGenFramebuffers(1, &frameID.frameID);
	glGenTextures(1, &frameID.textureID);
	glGenRenderbuffers(1, &frameID.RBO);
	m_frames[i] = frameID;

	glBindFramebuffer(GL_FRAMEBUFFER, frameID.frameID);

	// 获得窗口尺寸
	int width, height;
	glfwGetWindowSize(m_window, &width, &height);

	// 创建纹理附件
	glBindTexture(GL_TEXTURE_2D, frameID.textureID);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glBindTexture(GL_TEXTURE_2D, 0);

	// 创建渲染缓冲对象
	glBindRenderbuffer(GL_RENDERBUFFER, frameID.RBO);
	glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
	glBindRenderbuffer(GL_RENDERBUFFER, 0);

	// 绑定到当前帧缓冲
	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, frameID.textureID, 0);
	glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, frameID.RBO);

	// 检查帧缓冲是否完整
	if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
		std::cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << std::endl;

	// 解除绑定
	glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

void GLProgram::BindFrame(int i)
{
	if (m_frames.count(i) == 0)
	{
		std::cout << "Frame don't exist." << std::endl;
		return;
	}

	glBindFramebuffer(GL_FRAMEBUFFER, m_frames[i].frameID);
}

void GLProgram::UnbindFrame()
{
	glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

void GLProgram::GenerateScreenArray(int i)
{
	float quadVertices[] = {
		// positions	// textures
		-1.0f,  1.0f,  0.0f, 1.0f,
		-1.0f, -1.0f,  0.0f, 0.0f,
		 1.0f, -1.0f,  1.0f, 0.0f,

		-1.0f,  1.0f,  0.0f, 1.0f,
		 1.0f, -1.0f,  1.0f, 0.0f,
		 1.0f,  1.0f,  1.0f, 1.0f
	};

	// 生成顶点数组
	GenerateArray(i);
	BindArray(i);

	glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices[0], GL_STATIC_DRAW);

	glEnableVertexAttribArray(0);
	glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, (void*)0);

	glEnableVertexAttribArray(1);
	glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, (void*)(2 * sizeof(float)));

	UnbindArray();
}

void GLProgram::DrawScreen(int array, int frame)
{
	if (m_frames.count(frame) == 0)
	{
		std::cout << "Frame don't exist." << std::endl;
		return;
	}
	if (m_VAOs.count(array) == 0)
	{
		std::cout << "Array don't exist." << std::endl;
		return;
	}
	BindArray(array);

	// 激活纹理，绑定到帧缓冲附加的纹理，绑定纹理坐标到纹理变量
	ActiveTexture(0);
	glBindTexture(GL_TEXTURE_2D, m_frames[frame].textureID);
	SetUniformInt("screenTexture", 0);

	glDrawArrays(GL_TRIANGLES, 0, 6);

	UnbindTexture();
	UnbindArray();
}

void GLProgram::GenerateSkyboxArray(int i)
{
	float skyboxVertices[] = {
		// positions          
		-1.0f,  1.0f, -1.0f,
		-1.0f, -1.0f, -1.0f,
		 1.0f, -1.0f, -1.0f,
		 1.0f, -1.0f, -1.0f,
		 1.0f,  1.0f, -1.0f,
		-1.0f,  1.0f, -1.0f,

		-1.0f, -1.0f,  1.0f,
		-1.0f, -1.0f, -1.0f,
		-1.0f,  1.0f, -1.0f,
		-1.0f,  1.0f, -1.0f,
		-1.0f,  1.0f,  1.0f,
		-1.0f, -1.0f,  1.0f,

		 1.0f, -1.0f, -1.0f,
		 1.0f, -1.0f,  1.0f,
		 1.0f,  1.0f,  1.0f,
		 1.0f,  1.0f,  1.0f,
		 1.0f,  1.0f, -1.0f,
		 1.0f, -1.0f, -1.0f,

		-1.0f, -1.0f,  1.0f,
		-1.0f,  1.0f,  1.0f,
		 1.0f,  1.0f,  1.0f,
		 1.0f,  1.0f,  1.0f,
		 1.0f, -1.0f,  1.0f,
		-1.0f, -1.0f,  1.0f,

		-1.0f,  1.0f, -1.0f,
		 1.0f,  1.0f, -1.0f,
		 1.0f,  1.0f,  1.0f,
		 1.0f,  1.0f,  1.0f,
		-1.0f,  1.0f,  1.0f,
		-1.0f,  1.0f, -1.0f,

		-1.0f, -1.0f, -1.0f,
		-1.0f, -1.0f,  1.0f,
		 1.0f, -1.0f, -1.0f,
		 1.0f, -1.0f, -1.0f,
		-1.0f, -1.0f,  1.0f,
		 1.0f, -1.0f,  1.0f
	};

	// 生成顶点数组
	GenerateArray(i);
	BindArray(i);

	glBufferData(GL_ARRAY_BUFFER, sizeof(skyboxVertices), &skyboxVertices[0], GL_STATIC_DRAW);

	glEnableVertexAttribArray(0);
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 3, (void*)0);

	UnbindArray();
}

void GLProgram::DrawSkybox(int array, int texture)
{
	if (m_VAOs.count(array) == 0)
	{
		std::cout << "Array don't exist." << std::endl;
		return;
	}
	if (m_textures.count(texture) == 0)
	{
		std::cout << "Texture don't exist." << std::endl;
		return;
	}

	// 去除位移部分，使天空盒的位置向量不变
	glm::mat4 view = glm::mat4(glm::mat3(s_camera.GetViewMatrix()));
	SetUniformMatrix4fv("view", glm::value_ptr(view));

	BindArray(array);
	glDrawArrays(GL_TRIANGLES, 0, 36);
	UnbindArray();
}

void GLProgram::MessageLoop(std::function<void(void)> loader, std::function<void(void)> painter)
{
	// 加载顶点数据
	loader();

	// 开启消息循环
	while (!glfwWindowShouldClose(m_window))
	{
		// 检查键盘输入，如果为 ESC 就退出
		if (glfwGetKey(m_window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
			glfwSetWindowShouldClose(m_window, true);

		// 渲染指令
		painter();

		// 交换缓冲，处理并调用事件
		glfwSwapBuffers(m_window);
		glfwPollEvents();
	}
}

void GLFWWindowResize(GLFWwindow* window, int width, int height)
{
	glViewport(0, 0, width, height);
}

void GLFWMouseButtonCallback(GLFWwindow* window, int button, int action, int mode)
{
	if (button == GLFW_MOUSE_BUTTON_LEFT)
	{
		if (action == GLFW_PRESS)
			GLProgram::s_moving = true;
		if (action == GLFW_RELEASE)
			GLProgram::s_moving = false;
	}
}

void GLFWCursorPosCallback(GLFWwindow* window, double xpos, double ypos)
{
	static double px, py, rate = 0.5;

	if (GLProgram::s_moving)
	{
		float angleX = GLProgram::s_camera.GetYaw() + (xpos - px) * rate;
		float angleY = GLProgram::s_camera.GetPitch() + (ypos - py) * rate;

		GLProgram::s_camera.SetYaw(angleX);
		GLProgram::s_camera.SetPitch(angleY);
	}

	px = xpos;
	py = ypos;
}

void GLFWScrollCallback(GLFWwindow* window, double xoffset, double yoffset)
{
	float distance = GLProgram::s_camera.GetDistance();
	GLProgram::s_camera.SetDistance(distance - yoffset);
}
